/*
** Copyright (c) 2008 Mobile GCalendar
**
** Permission is hereby granted, free of charge, to any person
** obtaining a copy of this software and associated documentation
** files (the "Software"), to deal in the Software without
** restriction, including without limitation the rights to use,
** copy, modify, merge, publish, distribute, sublicense, and/or sell
** copies of the Software, and to permit persons to whom the
** Software is furnished to do so, subject to the following
** conditions:
**
** The above copyright notice and this permission notice shall be
** included in all copies or substantial portions of the Software.
**
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
** OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
** HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
** WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
** FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
** OTHER DEALINGS IN THE SOFTWARE.
*/

package au.edu.mq.comp.itec800.mgc.lib.calendar;

import java.security.InvalidParameterException;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;

import au.edu.mq.comp.itec800.mgc.lib.GCalendar;
import au.edu.mq.comp.itec800.mgc.lib.GCalendarManager;
import au.edu.mq.comp.itec800.mgc.lib.calendar.event.DateRange;
import au.edu.mq.comp.itec800.mgc.util.GDataUtils;
import au.edu.mq.comp.itec800.mgc.util.MGCUtils;
import au.edu.mq.comp.itec800.mgc.util.StringUtils;

import com.google.gdata.data.DateTime;
import com.google.gdata.data.calendar.CalendarEntry;
import com.google.gdata.data.calendar.CalendarEventEntry;
import com.google.gdata.data.extensions.BaseEventEntry;
import com.google.gdata.data.extensions.When;
import com.google.gdata.data.extensions.Where;


/**
 * A composite class for the GData API's CalendarEventEntry.
 *
 * This class provides a few more simplistic editing features for the
 * CalendarEventEntry and makes it easier to use by external software.
 *
 *
 * This classes calls converting and wrapping methods from the
 * mgc.util.GDataUtils class as well.
 *
 * This class could not be built as an extension like the GCalendar class
 * for CalendarEntry, because CalendarEventEntry does not provide a
 * shallow copy constructor !!
 *
 *
 * @see CalendarEventEntry
 * @see GDataUtils
 *
 * @author Laurent Malvert [laurent.malvert@students.mq.edu.au]
 */
public class GEvent
{
  private BaseEventEntry<CalendarEventEntry>  bevt  = null;
  private CalendarEventEntry                  cevt      = null;


  public GEvent()
  {
    this((CalendarEventEntry) null);
  }

  public GEvent(final BaseEventEntry<CalendarEventEntry> bevt)
  {
    this((CalendarEventEntry) bevt);
  }

  public GEvent(final CalendarEventEntry cevt)
  {
    this.cevt = (cevt != null) ? cevt : new CalendarEventEntry();
    bevt      = this.cevt;
  }

  public void         updateName(final String name)
  {
    if (name != null)
    {
      getEvent().setTitle(GDataUtils.toPlainTextConstruct(name));
    }
  }

  public void         updateDescription(final String description)
  {
    if (description != null)
    {
      getEvent().setContent(GDataUtils.toPlainTextConstruct(description));
    }
  }

  public void         updateLocation(final String location)
  {
    if (location != null)
    {
      getEvent().getLocations().clear();
      getEvent().addLocation(new Where("", "", location));
    }
  }

  public String       getShortId()
  {
    return (GDataUtils.getSafeId(getEvent()));
  }

  public boolean      isSameAs(final GCalendar cal2)
  {
    return ((cal2 != null) ? getShortId().equals(cal2) : false);
  }

  public boolean      isOwn()
   {
    return (getEvent().getId().indexOf("/own") != -1);
  }

  public String       getLocation()
  {
    final List<Where> locations = getEvent().getLocations();
    String            location  = "";

    if (locations.size() != 0)
    {
      location = StringUtils.sanitize(locations.get(0).getValueString());
    }
    return (location);
  }

  public String       getDescription()
  {
    return (StringUtils.sanitize(getEvent().getPlainTextContent()));
  }

  public String       getName()
  {
    return (GDataUtils.fromTextConstruct(getEvent().getTitle()));
  }

  public String       getStartTimeStamp()
  {
    final List<When>  whens  = getEvent().getTimes();

    return (DateRange.toStamp((whens.size() > 0) ? GDataUtils.fromDateTime(whens.get(0).getStartTime()) : DateRange.now()));
  }

  public String       getEndTimeStamp()
  {
    final List<When>  whens  = getEvent().getTimes();

    return (DateRange.toStamp((whens.size() > 0) ? GDataUtils.fromDateTime(whens.get(0).getEndTime()) : DateRange.now()));
  }

  /**
   * This method check whether a particular event is starting between a giving
   * set of dates.
   *
   * The start & end date should be in the following formats:<br />
   * <ul>
   *  <li>2008.06.28 15:30:45</li>
   *  <li>2008.06.28 15:30</li>
   *  <li>2008.06.28 15</li>
   *  <li>2008.06.28</li>
   *  <li>2008.06</li>
   *  <li>2008</li>
   * </ul>
   *
   * Additionally start can also be one of the following keywords:<br />
   * <ul>
   *  <li>daily</li>
   *  <li>weekly</li>
   *  <li>monthly</li>
   * </ul>
   *
   * If:<br />
   * <ul>
   *  <li>a keyword is used, the end argument is ignored;</li>
   *  <li>if start is null, a value of true is immediately returned;</li>
   *  <li>if an event is recurring true is returned.</li>
   * </ul>
   *
   *
   * @param start The starting date of the range
   * @param end   The ending date of the range
   * @return true if the event is starting between the giving range
   */
  public boolean      isInRange(final String start, String end)
  {
    boolean           status  = false;

    if ((start == null) || (getEvent().getRecurrence() != null))
    {
      status = true;
    }
    else
    {
      final Date      evtDate = DateRange.date(getStartTimeStamp());
      final DateRange range;

      if (start.equalsIgnoreCase("daily"))
      {
        range = DateRange.day(DateRange.dcalendar().getTime());
      }
      else if (start.equalsIgnoreCase("weekly"))
      {
        range = DateRange.week(DateRange.wcalendar().getTime());
      }
      else if (start.equalsIgnoreCase("monthly"))
      {
        range = DateRange.month(DateRange.mcalendar().getTime());
      }
      else
      {
        range = DateRange.range(start, (end == null) ? start : end);
      }
      status = evtDate.equals(range.getStart()) ||
        (evtDate.after(range.getStart()) &&
         (evtDate.before(range.getEnd()) || range.isAtomic()));
    }
    return (status);
  }

  public void         updateTime(final String start,
                                 final String end)
  {
    final CalendarEntry cal       = MGCUtils.getGAccount().getCalendarManager().getCurrentCalendar();
    final TimeZone      tz        = TimeZone.getTimeZone(GCalendarManager.getTimeZone(cal));
    final When          evtTimes  = new When();
    Date                startDate = null;
    Date                endDate   = null;

    try
    { // start = given start
      startDate = DateRange.date(start);
    }
    catch (final InvalidParameterException e)
    { // start was null or invalid -> start = now
      startDate = DateRange.now();
    }
    evtTimes.setStartTime(new DateTime(startDate, tz));
    try
    { // end = given date
      endDate = DateRange.date(end);
    }
    catch (final InvalidParameterException e)
    { // end was null or invalid -> end = start + 1H
      endDate = DateRange.nextHour(startDate);
    }
    evtTimes.setEndTime(new DateTime(endDate, tz));
    getEvent().getTimes().clear();
    getEvent().addTime(evtTimes);
  }

  public CalendarEventEntry                 getEvent()
  {
    return (cevt);
  }

  public BaseEventEntry<CalendarEventEntry> getBaseEvent()
  {
    return (bevt);
  }

}
